package com.wang.tx.core;


import java.util.ArrayList;
import java.util.List;

import static com.wang.tx.core.TccCallback.*;

public class TccUtils {
    // 当combine之后套上retry，会出现无意义的try,cancel调用，
    // 最好使用retry再套上combine.
    public static TccTransaction combine(long id, List<TccTransaction> list) {
        return new TccTransaction() {
            private List<TccTransaction> tryList = new ArrayList<>(list.size());

            @Override
            public long id() {
                return id;
            }

            @Override
            public boolean onTry() throws Exception {
                boolean tryResult = true;
                for (TccTransaction tx : list) {
                    try {
                        boolean r = tx.onTry();
                        if (r) {
                            tryList.add(tx);
                            continue;
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    tryResult = false;
                    break;
                }

                if (!tryResult) {
                    for (TccTransaction tx : tryList) {
                        tx.onCancel();
                    }
                }
                return tryResult;
            }

            @Override
            public void onConfirm() throws Exception {
                for (TccTransaction tx : tryList) {
                    tx.onConfirm();
                }
            }

            @Override
            public void onCancel() throws Exception {
                for (TccTransaction tx : tryList) {
                    tx.onCancel();
                }
            }
        };
    }

    public static TccTransaction emptyTx() {
        return new TccTransaction() {
            @Override
            public long id() {
                return 0;
            }

            @Override
            public boolean onTry() {
                return true;
            }

            @Override
            public void onConfirm() {
            }

            @Override
            public void onCancel() {
            }
        };
    }

    // 能重试的事务
    public static TccTransaction retry(TccTransaction transaction, int retryCount) {
        return new TccTransaction() {
            @Override
            public long id() {
                return transaction.id();
            }

            @Override
            public boolean onTry() throws Exception {
                Exception lastException = null;
                int i = 0;
                boolean r = false;
                while (i < retryCount && !r) {
                    try {
                        r = transaction.onTry();
                    } catch (Exception e) {
                        lastException = e;
                    }
                    i++;
                }
                if (lastException != null) throw lastException;
                return i < retryCount;
            }

            @Override
            public void onConfirm() throws Exception {
                Exception lastException = null;
                int i = 0;
                while (i < retryCount) {
                    try {
                        transaction.onConfirm();
                        break;
                    } catch (Exception e) {
                        lastException = e;
                    }
                    i++;
                }
                if (lastException != null) throw lastException;
            }

            @Override
            public void onCancel() throws Exception {
                Exception lastException = null;
                int i = 0;
                while (i < retryCount) {
                    try {
                        transaction.onCancel();
                        break;
                    } catch (Exception e) {
                        lastException = e;
                    }
                    i++;
                }
                if (lastException != null) throw lastException;
            }
        };
    }


    public static boolean run(int state, List<TccTransaction> txList, List<TccTransaction> tryList, TccCallback callback) throws Exception {
        if (state == SUCCESS) {
            return true;
        } else if (state == FAIL) {
            return false;
        }

        boolean tryR = true;
        if(state == TRY_OK) {
            tryR = true;
        } else if (state == TRY_FAIL) {
            tryR = false;
        } else if (state == INIT) {
            tryList = new ArrayList<>(txList.size());
            for (TccTransaction tx : txList) {
                boolean r = tx.onTry();
                if (!r) {
                    tryR = false;
                    break;
                }
                tryList.add(tx);
            }
            if(tryR) {
                callback.trySuccess();
            } else {
                callback.tryFail(tryList);
            }
        } else throw new Error();

        if(tryR) {
            for (TccTransaction tx : tryList) {
                tx.onConfirm();
            }
            callback.txSuccess();
        } else {
            for (TccTransaction tx : tryList) {
                tx.onCancel();
            }
            callback.txFail();
        }

        return tryR;
    }

}
